/*	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------*/
/*!	@file	<os.h>
	@path	~/src/config/
	@date	2007/06/14
	@desc	Platform related declarations.
*/

/* ANSI C compatible. */

#pragma once

#include "xeres.h"

#include "config/config.h"

/* Some constants. */
#define	DIR_SEPARATOR			'\\'
#define	PATH_ENV_SEPARATOR		';'
#define	OS_MAX_PATH				(260)
#define	OS_MAX_HOST				(64)
#define	SUB_PATH_MAX			(256)

/* Setup system configuration. */
#ifndef _FULLAPI
#define WIN32_LEAN_AND_MEAN
#endif /*_FULLAPI*/

/* Support to Windows Vista (6.0). */
#define _WIN32_WINNT			0x0600

/* Windows API. */
#include "windows.h"

#if ( WINVER < 0x0501 )
#error Windows SDK expects version 0x0501 (XP)!
#endif

/* If SDK version < 0x0600 , change to older version _WIN32_WINNT. */
#if WINVER < 0x0600
#undef _WIN32_WINNT
#define _WIN32_WINNT			0x0501
#endif

/* Manifest build embedded, for common control. */
#if defined _M_IX86
#	pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#	pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#	pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#	pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif

/* Manifest build embedded, for GDI+ 1.1. */
#ifdef GDIPLUS_1_1
#if defined _M_IX86
#	pragma comment(linker,"/manifestdependency:\"type='Win32' name='Microsoft.Windows.GdiPlus' version='1.1.6001.18000' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#	pragma comment(linker,"/manifestdependency:\"type='Win32' name='Microsoft.Windows.GdiPlus' version='1.1.6001.18000' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#	pragma comment(linker,"/manifestdependency:\"type='Win32' name='Microsoft.Windows.GdiPlus' version='1.1.6001.18000' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#	pragma comment(linker,"/manifestdependency:\"type='Win32' name='Microsoft.Windows.GdiPlus' version='1.1.6001.18000' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif /*GDIPLUS_1_1*/


/* A well-known trick for VC debug */

#if ( defined _DEBUG ) && ( ( defined _MSC_VER ) || ( defined __ICL ) )

#define MS_VC_EXCEPTION 0x406D1388

typedef struct tagTHREADNAME_INFO
{
    DWORD dwType;       /* Must be 0x1000.*/
    LPCSTR szName;      /* Pointer to name (in user addr space).*/
    DWORD dwThreadID;   /* Thread ID (-1=caller thread).*/
    DWORD dwFlags;      /* Reserved for future use, must be zero.*/
} THREADNAME_INFO;

/*! \brief	Set local thread name in VC debugging environment.	*/
static void SetThreadName( DWORD dwThreadID , LPCSTR szThreadName )
{
    THREADNAME_INFO info;
    info.dwType     = 0x1000;
    info.szName     = szThreadName;
    info.dwThreadID = dwThreadID;
    info.dwFlags    = 0;
    __try
    {
        RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_CONTINUE_EXECUTION)
    {
    }
}

#undef MS_VC_EXCEPTION

#else

static void SetThreadName( DWORD , LPCSTR )
{
}

#endif /*_DEBUG*/

/* The following functions are only available in C++. */
#ifdef __cplusplus
namespace xeres {

	// Prints Win32 error to trace.
	static void __win32_error( const wchar_t * printf_format , DWORD err = GetLastError() );

#ifndef _DOC_GEN
	// Normalize slashes to system specified slash.
	template< typename _iter > static void normalize_slash( _iter filename );

	// Normalize slashes to system specified slash.
	template< typename _iter >static void normalize_slash( _iter begin , _iter end );
#endif /*_DOC_GEN*/

	/*!
		\name	Spin Lock
		\details
				A simple & small lock mechanism, which wait by spin and yield.
				Usually a spin lock is an integer.<BR>
				In complex situation, e.g. in some lock debugging mode,
				a lock should contains threads which locking it.
		@{
	*/

	/*!
		\enum	LockState
		\brief	A lock has 2 states: free or taken.
	*/
	enum LockState { LOCK_FREE = 0 , LOCK_TAKEN = 1 };

	/*!
		\var		SPIN_LOCK_DEFAULT_SPIN_COUNT
		\brief		Default spin count for spin lock.
	*/
	static const int SPIN_LOCK_DEFAULT_SPIN_COUNT = 50;

	/*!
		\brief		Initialize spin lock state.
	*/
	static void spin_lock_init( int * spin_lock );

	/*!
		\brief		Do self spin, and wait, and return if lock is free.
	*/
	static void spin_spin( int volatile * spin_lock , int spin_count = SPIN_LOCK_DEFAULT_SPIN_COUNT );

	/*!
		\brief		Do self spin, and wait, and return if lock is free.
	*/
	static bool spin_spin_val( int volatile * spin_lock , const int comparison , int spin_count = SPIN_LOCK_DEFAULT_SPIN_COUNT );

	/*!
		\brief		Get ownership of lock. Wait until lock is owned.
	*/
	static void spin_lock_lock( int volatile * spin_lock , int spin_count = SPIN_LOCK_DEFAULT_SPIN_COUNT );

	/*!
		\brief		Try to get the lock ownership, and return result immediately, do not wait.
		\return		Lock state, taken or free.
					Free means the lock is taken just now by this call.
					Taken means the lock is still taken by other thread.
	*/
	static LockState spin_lock_trylock( int volatile * spin_lock );

	/*!
		\brief		Release current lock.
	*/
	static void spin_lock_unlock( int volatile * spin_lock );

	/*!
		@}
	*/

	/*!
		\name	Atomic operation functions
		@{
	*/

	/*!
		\brief		Atomic increment of 32 bit integer.
	*/
	static void atom_inc( int volatile * var );

	/*!
		\brief		Atomic decrement of 32 bit integer.
	*/
	static void atom_dec( int volatile * var );

	/*!
		\brief		Add a value to var atomically.
	*/
	static void atom_add( int volatile * var , int value );

	/*!
		\brief		Add a value to var atomically and return the value before add.
	*/
	static int atom_xchg_add( int volatile * var , int value );

	/*!
		\brief		Atomically exchange 2 value.
	*/
	static int atom_xchg( int volatile * var , int value );

	/*!
		\brief		Exchange 2 pointers with interlocked.
	*/
	static void * __fastcall atom_xchg_ptr( void * volatile * dst , void * src );

	/*!
		\brief		Compare & exchange 2 pointers with interlocked.
	*/
	static void * atom_cmpxchg_ptr( void * volatile * dst , void * src , void * comparend );

	/*!
		@}
	*/

} // namespace xeres

#include "config/os.inl"

#endif /* __cplusplus */
